package com.beiding.workordersystem.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.beiding.workordersystem.common.helper.SessionHolder;
import com.beiding.workordersystem.common.observer.UserObserver;
import com.beiding.workordersystem.common.service.BaseService;
import com.beiding.workordersystem.common.standard.E;
import com.beiding.workordersystem.common.utils.TreeUtils;
import com.beiding.workordersystem.system.dao.*;
import com.beiding.workordersystem.system.entity.*;
import com.beiding.workordersystem.system.service.RoleService;
import com.google.common.collect.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class RoleServiceImpl extends BaseService implements RoleService , UserObserver {

    @Autowired
    private RoleAccountDao roleAccountDao;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private RoleAuthorityDao roleAuthorityDao;

    @Autowired
    private AuthorityDao authorityDao;

    @Autowired
    private AccountDao accountDao;

    @Autowired
    private SessionHolder sessionHolder;

    @Autowired
    private UserDao userDao;

    @Override
    public List<RoleEntity> listByUserId(String id) {
        List<RoleAccountRelation> list = roleAccountDao.selectList(new QueryWrapper<RoleAccountRelation>().lambda().eq(RoleAccountRelation::getAccountId, id));

        if (list.size() > 0) {

            List<RoleEntity> roleEntities = roleDao.selectList(new QueryWrapper<RoleEntity>().lambda().in(RoleEntity::getId, list.stream().map(RoleAccountRelation::getRoleId).collect(Collectors.toList())));
            if (roleEntities.size() > 0) {
                roleEntities.forEach(this::fillAuthority);
            }

            return roleEntities;

        } else {
            return Collections.emptyList();
        }
    }

    private void fillAuthority(RoleEntity o) {
        List<RoleAuthorityRelation> selectList = roleAuthorityDao.selectList(new QueryWrapper<RoleAuthorityRelation>().lambda().eq(RoleAuthorityRelation::getRoleId, o.getId()));
        if (selectList.size() > 0) {
            List<AuthorityEntity> authorityEntities = authorityDao.selectList(new QueryWrapper<AuthorityEntity>().lambda().in(AuthorityEntity::getId, selectList.stream().map(RoleAuthorityRelation::getAuthorityId).collect(Collectors.toList())));
            o.setAuthorities(new HashSet<>(authorityEntities));
        } else {
            o.setAuthorities(Collections.emptySet());
        }
    }
    private void fillUser(RoleEntity o) {
        List<RoleAccountRelation> selectList = roleAccountDao.selectList(new QueryWrapper<RoleAccountRelation>().lambda().eq(RoleAccountRelation::getRoleId, o.getId()));
        if (selectList.size() > 0) {
            List<UserEntity> userEntities = userDao.selectList(new QueryWrapper<UserEntity>().lambda().in(UserEntity::getAccountId, selectList.stream().map(RoleAccountRelation::getAccountId).collect(Collectors.toList())));
            o.setUsers(new HashSet<>(userEntities));
        } else {
            o.setUsers(Collections.emptySet());
        }
    }

    @Override
    public void save(RoleEntity roleEntity) {

        E.isTrue(roleDao.exist(new QueryWrapper<RoleEntity>().lambda().eq(RoleEntity::getId, roleEntity.getPid())), "给定的父节点不存在");

        if (StringUtils.isEmpty(roleEntity.getId())) {
            E.isFalse(roleDao.exist(new QueryWrapper<RoleEntity>().lambda().eq(RoleEntity::getRole, roleEntity.getRole()).or().eq(RoleEntity::getName, roleEntity.getName())), "角色名称或标识已存在");
            roleEntity.setId(createId());
            roleDao.insert(roleEntity);
        } else {
            RoleEntity select = roleDao.selectById(roleEntity.getId());
            E.isTrue(select != null, "角色", roleEntity.getName(), "不存在");

            if (select.getPid().equals(roleEntity.getPid())) {
                //TODO 角色上级变换测试
                TreeUtils.fillChildren(select, "children", o -> roleDao.selectList(new QueryWrapper<RoleEntity>().lambda().eq(RoleEntity::getPid, o.getId())));
                List<RoleEntity> roleEntities = TreeUtils.childrenUnfold(select, "children");
                roleEntities.add(select);
                for (RoleEntity entity : roleEntities) {
                    if (entity.getId().equals(roleEntity.getPid())) {
                        E.error("无效的等级关系");
                    }
                }
            }

            E.isFalse(roleDao.exist(new QueryWrapper<RoleEntity>().lambda().eq(RoleEntity::getRole, roleEntity.getRole()).or().eq(RoleEntity::getName, roleEntity.getName()).ne(RoleEntity::getId, roleEntity.getId())), "角色名称或标识已存在");
            roleDao.updateById(roleEntity);
        }
    }

    @Override
    public RoleEntity getAndFillChildren(String id) {
        RoleEntity roleEntity = roleDao.selectById(id);
        E.isTrue(roleEntity != null, "节点未找到");
        TreeUtils.fillChildren(roleEntity, "children", o -> roleDao.selectList(new QueryWrapper<RoleEntity>().lambda().eq(RoleEntity::getPid, o.getId())));
        return roleEntity;
    }

    private boolean existRoleById(String id) {
        return roleDao.exist(new QueryWrapper<RoleEntity>().lambda().eq(RoleEntity::getId, id));
    }


    private Set<String> usernameFromIds(Set<String> ids) {
        if (ids.size() == 0) {
            return Collections.emptySet();
        }
        return accountDao.selectList(new QueryWrapper<AccountEntity>().lambda().in(AccountEntity::getId, ids)).stream().map(AccountEntity::getUsername).collect(Collectors.toSet());
    }

    private Set<String> associateAccounts(String roleId) {
        List<RoleAccountRelation> list = roleAccountDao.selectList(new QueryWrapper<RoleAccountRelation>().lambda().eq(RoleAccountRelation::getRoleId, roleId));

        if (list.size() == 0) {
            return Collections.emptySet();
        }

        List<AccountEntity> accountEntities = accountDao.selectList(new QueryWrapper<AccountEntity>()
                .lambda().in(AccountEntity::getId, list.stream().map(RoleAccountRelation::getAccountId).collect(Collectors.toSet())));
        return accountEntities.stream().map(AccountEntity::getUsername).collect(Collectors.toSet());
    }


    @Override
    @Transactional
    public void associateAuthority(String roleId, Set<String> authorityIds) {
        E.isTrue(!roleId.equals("0"), "无法对超管操作");
        E.isTrue(existRoleById(roleId), "角色不存在");
        roleAuthorityDao.delete(new QueryWrapper<RoleAuthorityRelation>().lambda().eq(RoleAuthorityRelation::getRoleId, roleId));
        for (String authorityId : authorityIds) {
            E.isTrue(authorityDao.exist(new QueryWrapper<AuthorityEntity>().lambda().eq(AuthorityEntity::getId, authorityId)), "权限不存在");
            RoleAuthorityRelation roleAuthorityRelation = new RoleAuthorityRelation();
            roleAuthorityRelation.setId(createId());
            roleAuthorityRelation.setRoleId(roleId);
            roleAuthorityRelation.setAuthorityId(authorityId);
            roleAuthorityRelation.setCreateTime(current());
            roleAuthorityDao.insert(roleAuthorityRelation);
        }

        //移除角色所有关联的账户
        Set<String> accounts = associateAccounts(roleId);

        for (String account : accounts) {
            sessionHolder.forceOffline(account);
        }

    }

    @Override
    @Transactional
    public void associateAccount(String roleId, Set<String> accountIds) {
        E.isTrue(!roleId.equals("0"), "无法对超管操作");
        E.isTrue(existRoleById(roleId), "角色不存在");
        Set<String> oldIds = associateAccounts(roleId);
        roleAccountDao.delete(new QueryWrapper<RoleAccountRelation>().lambda().eq(RoleAccountRelation::getRoleId, roleId));
        for (String accountId : accountIds) {
            E.isTrue(accountDao.exist(new QueryWrapper<AccountEntity>().lambda().eq(AccountEntity::getId, accountId)), "账户不存在");
            RoleAccountRelation roleAccountRelation = new RoleAccountRelation();
            roleAccountRelation.setId(createId());
            roleAccountRelation.setRoleId(roleId);
            roleAccountRelation.setAccountId(accountId);
            roleAccountRelation.setCreateTime(current());
            roleAccountDao.insert(roleAccountRelation);
        }

        Set<String> nowIds = usernameFromIds(accountIds);
        Sets.SetView<String> difference = Sets.difference(oldIds, nowIds);
        for (String s : difference) {
            sessionHolder.forceOffline(s);
        }
    }

    @Override
    public void delete(String id) {
        boolean exist = roleAccountDao.exist(new QueryWrapper<RoleAccountRelation>().lambda().eq(RoleAccountRelation::getRoleId, id));
        E.isFalse(exist, "角色下关联用户不可删除");
        roleDao.deleteById(id);
    }

    @Override
    public RoleEntity getDetails(String id) {
        RoleEntity roleEntity = roleDao.selectById(id);
        if (roleEntity != null) {
            fillAuthority(roleEntity);
            fillUser(roleEntity);
        }
        return roleEntity;
    }



    @Override
    public void afterDelete(String userId, String accountId, String nmae) {
        roleAccountDao.delete(new QueryWrapper<RoleAccountRelation>().lambda().eq(RoleAccountRelation::getAccountId, accountId));
    }

}
